import logging

import cherrypy
from cherrypy import NotFound

import turbogears
from turbogears import controllers, expose, validate, redirect, validators
from turbogears import identity, view

from cgi import escape
import re

from model import *

from datetime import datetime, timedelta

from arkivo import json

log = logging.getLogger("arkivo.controllers")

URL_REGEXP = re.compile(r'((http|https|ftp|gopher|news)://[^ \'")>]*)')

# Variable provider for bot status
def bot_status_provider (vars):
    vars["bot_is_online"] = Setting.byName("is_online").data
    
view.variable_providers.append(bot_status_provider)

class ArchiveController(controllers.Controller):
    
    @expose()
    def index(self):
        redirect("/")
        
    @expose(template="arkivo.templates.archive")
    def default(self, *args, **kw):
        
        old_url = Channel.select(Channel.q.name==args[0]).count()
        if old_url > 0:
            turbogears.flash("Our URL's have changed due to additional features. Please update your bookmarks.")
            redirect("/")

        args = list(args)
        service = args.pop(0)
        name = args.pop(0)
        
        ptype = None
        message_select = None
        arc_date = None
        try:
            service = Service.byName(service)
            channel = Channel.select(AND(Channel.q.serviceID==service.id, Channel.q.name==name))[:1][0]
        except SQLObjectNotFound:
            raise NotFound
            
        #lets see if we have a year/month/day on the url
        try:
            urldate = [int(arg) for i,arg in enumerate(args) if i < 3]
        except ValueError:
            raise NotFound
            
        selectargs = [Message.q.channelID == channel.id]        
        if len(urldate) > 0:
            if len(urldate) == 1:
                #we're getting a year's worth here...  not reccomended
                #in fact, prevent it from happening...
                raise NotFound
                
                start_date = datetime(urldate[0], 1, 1)
                end_date = datetime(urldate[0]+1, 1, 1) - timedelta(1)
                ptype = "Archive for %s" % start_date.strftime('%Y')
                selectargs.append(Message.q.time >= start_date)
                selectargs.append(Message.q.time <= end_date)
            elif len(urldate) == 2:
                #One month's worth...  again, a lot of data.
                raise NotFound
                
                start_date = datetime(urldate[0], urldate[1], 1)
                end_date = datetime(urldate[0], urldate[1] + 1, 1) - timedelta(1)
                ptype = "Archive for %s" % start_date.strftime('%B, %Y')
                selectargs.append(Message.q.time >= start_date)
                selectargs.append(Message.q.time <= end_date)
            elif len(urldate) == 3:
                try:
                    _url_datetime = datetime(urldate[0], urldate[1], urldate[2])
                except ValueError:
                    raise NotFound
                
                start_date = _url_datetime
                end_date = _url_datetime + timedelta(1)
                ptype = "Archive for %s" % _url_datetime.strftime('%d %B, %Y')
                selectargs.append(Message.q.time >= start_date)
                selectargs.append(Message.q.time < end_date)
                arc_date = _url_datetime
                
            message_select = Message.select(AND(*selectargs))
        else:
            message_select = channel.last_messages()
            ptype = "Last 100 messages"
            
        class SmartMessage:
            def __init__(self, this, last_time):
                self.time = this.time
                self.nick = this.nick
                self.line = self.linkify(this.line)
                self.isaction = this.isaction
                if last_time is not None:
                    self.last_time = last_time
                else:
                    self.last_time = None
                
            def day_changed(self):
                changed = True
                if self.last_time is not None:
                    this_tuple = (self.time.year, self.time.month, self.time.day)
                    last_tuple = (self.last_time.year, self.last_time.month, self.last_time.day)
                    if this_tuple == last_tuple:
                        changed = False
                return changed
                
            def linkify(self, text):
                text = escape(text)
                return URL_REGEXP.sub(r'<a href="\1">\1</a>', text)
                
        messages = []
        last_time = None
        message_select = list(message_select)
        for m in message_select:
            messages.append(SmartMessage(m, last_time))
            last_time = m.time
        
        try:    
            last_msg = Message.select(Message.q.channelID == channel.id)[-1:][0]
            last_date = last_msg.time.strftime("%Y-%m-%d")
        except IndexError:
            last_msg = None
            last_date = None
            
        if arc_date is None and last_msg is not None:
            arc_date = last_msg.time
        
        if arc_date is not None:    
            arc_date = arc_date.strftime("%Y-%m-%d")
        
        try:
            first_message = Message.select(Message.q.channelID == channel.id)[:1][0]
            first_date = first_message.time.strftime("%Y-%m-%d")
        except IndexError:
            first_message = None
            first_date = None
            
        return dict(service=service,
                    channel=channel,
                    messages=messages,
                    ptype=ptype,
                    arc_date = arc_date,
                    first_date = first_date,
                    last_date = last_date)
        
class Root(controllers.RootController):
    
    archive = ArchiveController()
    
    @expose(template="arkivo.templates.welcome")
    def index(self):
        live_channels = Channel.select(Channel.q.enabled == True)
        old_channels = Channel.select(Channel.q.enabled == False)
        return dict(live_channels=live_channels, old_channels=old_channels)
    
    @expose(template="arkivo.templates.about")
    def about(self):
        return dict()
        
    @expose()
    def search(self, *args, **kw):
        return "Not Implimented"
        
    @expose(template="arkivo.templates.login")
    def login(self, forward_url=None, previous_url=None, *args, **kw):

        if not identity.current.anonymous \
            and identity.was_login_attempted() \
            and not identity.get_identity_errors():
            raise redirect(forward_url)

        forward_url=None
        previous_url= cherrypy.request.path

        if identity.was_login_attempted():
            msg=_("The credentials you supplied were not correct or "
                   "did not grant access to this resource.")
        elif identity.get_identity_errors():
            msg=_("You must provide your credentials before accessing "
                   "this resource.")
        else:
            msg=_("Please log in.")
            forward_url= cherrypy.request.headers.get("Referer", "/")
        cherrypy.response.status=403
        return dict(message=msg, previous_url=previous_url, logging_in=True,
                    original_parameters=cherrypy.request.params,
                    forward_url=forward_url)

    @expose()
    def logout(self):
        identity.current.logout()
        raise redirect("/")
